﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CCWin;
using CCWin.SkinControl;
using System.Runtime.InteropServices;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using CCWin.SkinClass;
using GroupChat2013.Main.Controls;
using GroupChat2013.Entity;
using GroupChat2013.Common;
using GroupChat2013.Interface;
using GroupChat2013.Logic.Message;
using System.Collections;
using GroupChat2013.Logic;
using GroupChat2013.Logic.Interface;
using GroupChat2013.Data;
using GroupChat2013.Service;
using GroupChat2013.Main.Properties;

namespace GroupChat2013.Main
{
    public partial class FrmChat : CCSkinMain, IChat
    {
        #region 变量

        /// <summary>
        /// 当前登录用户
        /// </summary>
        public UserInfo m_CurrentUser
        {
            get { return EngineContext.Current.CurrUserInfo; }
        }

        /// <summary>
        /// 对方信息
        /// </summary>
        public FriendInfo m_FriendInfo;

        /// <summary>
        /// 消息管理
        /// </summary>
        private IMessage m_ChatMessage;

        private ObjTalker m_ObjTalker;

        /// <summary>
        /// 记录最近聊天信息
        /// </summary>
        private RecChatRepository m_RecChatRepository;

        private bool m_HasItem = true;

        private AutoResetEvent m_AutoReset = new AutoResetEvent(false);

        /// <summary>
        /// 发送聊天信息队列
        /// </summary>
        private Queue m_MessageQueue;

        /// <summary>
        /// 发送信息线程
        /// </summary>
        private Thread m_SendThread;

        /// <summary>
        /// 通知栏
        /// </summary>
        private AnnounceConfigInfo m_AnnounceConfigInfo { get; set; }

        private FrmChatRecord frmChatRecord;

        #endregion

        #region 事件


        #endregion

        #region 构造函数

        public FrmChat(FriendInfo friendInfo)
        {
            InitializeComponent();
            m_FriendInfo = friendInfo;

            //创建消息处理
            m_ChatMessage = new UserMessage(EngineContext.Current.CurrUserInfo, m_FriendInfo.userInfoId);

            chatPanel.messageManage = m_ChatMessage;

            m_ObjTalker = new ObjTalker() { TypeChat = ChatType.User, FriendInfo = m_FriendInfo };

            this.chatPanel.CreateMsgAfter += new ChatPanel.CreateMsgEventHandler(chatPanel_CreateMsgAfter);
            this.chatPanel.DragDrop += new DragEventHandler(chatPanel_DragDrop);
            this.chatPanel.DragEnter += new DragEventHandler(chatPanel_DragEnter);
            this.chatPanel.SendFile += (s, data) =>
            {
                foreach (string filePath in data)
                {
                    FileSend(filePath);
                }
            };

            //点击聊天记录按钮
            this.chatPanel.ChatRecordClickedHandler += () =>
            {
                //string url = ServiceUrlProxy.GetInstance().UserChatMsgURL(m_CurrentUser.UserName, m_CurrentUser.CID, m_FriendInfo.userInfoId);
                //FrmGroup.OpenWithChrome(url);

                if (frmChatRecord == null || frmChatRecord.IsDisposed)
                {
                    frmChatRecord = new FrmChatRecord(m_ChatMessage, ChatType.User, friendInfo.userInfoId, friendInfo.loginName);
                    frmChatRecord.Show(new Rectangle(this.Location, new Size(this.Width, this.Height)));
                }
                else frmChatRecord.Close();
            };

            this.chatPanel.SendKeyDownHandler += new KeyEventHandler(chatPanel_SendKeyDownHandler);

            this.btnSend.ButtonClick += new EventHandler(btnSend_ButtonClick);
            this.FormClosing += new FormClosingEventHandler(FrmChat_FormClosing);
            this.FormClosed += new FormClosedEventHandler(FrmChat_FormClosed);

            this.Activated += new EventHandler(FrmChat_Activated);

            this.flashTimer.Tick += new EventHandler(flashTimer_Tick);

            this.imgyy2.Click += new EventHandler(imgyy2_Click);

            this.Move += new EventHandler(FrmChat_Move);
        }

        private void FrmChat_Move(object sender, EventArgs e)
        {
            if (frmChatRecord != null && !frmChatRecord.IsDisposed)
            {
                frmChatRecord.SetLocation(new Rectangle(this.Location, new Size(this.Width, this.Height)));
            }
        }

        #endregion

        #region 发送消息相关

        /// <summary>
        /// 初始化发送队列
        /// </summary>
        private void InitSendQueue()
        {
            m_MessageQueue = Queue.Synchronized(new Queue());
            m_SendThread = new Thread(new ThreadStart(() =>
            {
                while (m_HasItem)
                {
                    if (m_MessageQueue.Count > 0)
                    {
                        SendMessage sendMessage = m_MessageQueue.Dequeue() as SendMessage;
                        if (sendMessage != null)
                        {
                            SendChatMessage(sendMessage);
                        }
                    }
                    else
                    {
                        m_AutoReset.WaitOne();
                    }
                }
            }));
            m_SendThread.IsBackground = true;
            m_SendThread.Start();
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="content"></param>
        /// <param name="appendAction"></param>
        private void SendChatMessage(SendMessage sendMessage)
        {
            List<MessageInfo> mcList = m_ChatMessage.SendMessage(sendMessage.MessageContent, sendMessage.ImagePathList, m_CurrentUser.CID);

            this.BeginInvoke(new Action(() =>
            {
                //加入消息记录区
                //this.chatPanel.SendToRichTextBox(sendMessage.MessageContent, true);
                this.chatPanel.ClearSendImageCache();

                //发送成功后将接收到的信息添加到消息记录区
                if (mcList != null && mcList.Count > 0)
                {
                    mcList.ForEach(x =>
                    {
                        if (x.MessageContent.FromId == m_CurrentUser.UserId)
                            this.chatPanel.SendToRichTextBox(sendMessage.MessageContent, true);
                        else
                            this.chatPanel.ReceiveToRichTextBox(x.MessageContent);
                    });
                }
                else //发送失败
                {
                    chatPanel.WriteNoticeToRichTextBox("消息发送失败！  " + sendMessage.MessageContent.Content);
                }
            }));

            //添加到最近聊天记录
            AddRecChat();
        }

        /// <summary>
        /// 将消息添加到队列中
        /// </summary>
        /// <param name="content"></param>
        private void EnqueueMessage(SendMessage sendMessage)
        {
            m_MessageQueue.Enqueue(sendMessage);
            m_AutoReset.Set();
        }

        private void btnSend_ButtonClick(object sender, EventArgs e)
        {
            this.chatPanel.SendMsg();
        }

        /// <summary>
        /// 快捷键发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chatPanel_SendKeyDownHandler(object sender, KeyEventArgs e)
        {
            bool canSend = false;
            if (btnSend.SendMode == SendMode.ENTER)
            {
                canSend = e.KeyValue == 13;
            }
            else if (btnSend.SendMode == SendMode.CTRLENTER)
            {
                canSend = e.Control && e.KeyValue == 13;
            }
            else if (btnSend.SendMode == SendMode.ALTS)
            {
                canSend = e.Alt && e.KeyValue == 83;
            }

            if (canSend)
            {
                this.chatPanel.SendMsg();

                e.Handled = true;
            }
        }

        #endregion

        #region 当消息创建后发送到服务器

        private void chatPanel_CreateMsgAfter(object sender, MessageContent msg)
        {
            if (m_FriendInfo.userInfoId == m_CurrentUser.UserId)
            {
                MessageBoxEx.Show("不能给自己发送消息", "提示",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            msg.FromId = m_CurrentUser.UserId;
            msg.FromName = m_CurrentUser.UserName;

            List<MyPicture> pictures = this.chatPanel.GetSendPicture();
            List<string> imageList = new List<string>();
            if (pictures != null)//如果文件是截图
            {
                //x.MD5.Length == 32 表示是截图或者插入的图片，因为
                //保存的图片名称是GUID 长度32
                pictures.ForEach(x => { if (x.MD5.Length == 32) imageList.Add(x.MD5); });
            }

            SendMessage sm = new SendMessage() { ImagePathList = imageList, MessageContent = msg };
            EnqueueMessage(sm);
            this.chatPanel.ClearSendMsgTextBox();
        }

        #endregion

        #region 接收服务器的聊天信息

        /// <summary>
        /// 更新聊天信息
        /// </summary>
        public void UpdateChatMessage()
        {
            AsyncClient.AsyncCall<List<MessageInfo>>(() =>
            {
                return m_ChatMessage.ReceiverMessage(m_CurrentUser.CID);
            },
            (mcList) =>
            {
                this.BeginInvoke(new Action(() =>
                {
                    mcList.ForEach(x =>
                    {
                        chatPanel.ReceiveToRichTextBox(x.MessageContent);
                    });

                    if (mcList != null && mcList.Count > 0 &&
                        WinApi.GetActiveWindow() != this.Handle)
                    {
                        MyFlashWindow(this, true);
                    }
                }));

                //添加到最近聊天记录
                AddRecChat();
            });
        }

        #endregion

        #region 文件发送

        private void chatPanel_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.All;
            else if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.All;
        }

        private void chatPanel_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] MyFiles;
                int i;
                // 将文件赋给一个数组。
                MyFiles = (string[])(e.Data.GetData(DataFormats.FileDrop));
                // 循环处理数组并将文件添加到列表中。
                for (i = 0; i <= MyFiles.Length - 1; i++)
                {
                    System.IO.FileInfo f = new System.IO.FileInfo(MyFiles[i]);
                    if (f.Exists)
                    {
                        if (!FileSend(f.FullName))
                        {
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ToolFile_ButtonClick(object sender, EventArgs e)
        {
            OpenFileDialog Dlg = new OpenFileDialog();
            FileInfo fileInfo;
            Dlg.Filter = "所有文件(*.*)|*.*";
            Dlg.CheckFileExists = true;

            if (Dlg.ShowDialog() == DialogResult.OK)
            {
                fileInfo = new FileInfo(Dlg.FileName);
                FileSend(fileInfo.FullName);

                tsbUploadFile_Click(tsbUploadFile, null);
            }
        }

        #endregion

        #region 窗体事件

        /// <summary>
        /// 窗口加载时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmChat_Load(object sender, EventArgs e)
        {
            this.uploadPanel.m_OrgX = 10;
            this.uploadPanel.m_OrgY = 1;

            //lblChatName.Text = string.Format("{0} ({1})", m_FriendInfo.loginName, m_FriendInfo.username);
            lblChatName.Text = m_FriendInfo.loginName;

            TopMost = false;

            this.Location = Program.GetLocation(this.Width, this.Height);

            InitSendQueue();
            this.chatPanel.InitDownloadImgQueue();

            this.UpdateChatMessage();

            InitChatConfig();

            InitPersonAppList();

            InitAnnounce();

            //通知窗体已经打开
            EngineContext.Current.ChatManager.NoticeChatOpened(m_FriendInfo.userInfoId);

            tsbAppList_Click(tsbAppList, null);
        }

        private void InitChatConfig()
        {
            ChatConfigInfo configInfo = EngineContext.Current.ChatConfig.Parse();
            this.chatPanel.SetFontStyle(configInfo);
            this.btnSend.configInfo = configInfo;
            this.btnSend.SendMode = (SendMode)Enum.Parse(typeof(SendMode), configInfo.SendMode.ToString());
        }

        /// <summary>
        /// 窗体关闭时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmChat_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (uploadPanel.ControlCount > 0)
            {
                DialogResult result = MessageBoxEx.Show("如果关闭窗口，将会中止文件传输。是否关闭窗口？", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
                if (result == DialogResult.OK)
                {
                    m_HasItem = false;
                    m_AutoReset.Set();

                    try { m_SendThread.Abort(); }
                    catch { }

                    uploadPanel.CancelAllUpload();

                    e.Cancel = false;
                }
                else
                    e.Cancel = true;
            }
        }

        /// <summary>
        /// 窗体关闭后
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmChat_FormClosed(object sender, FormClosedEventArgs e)
        {
            EngineContext.Current.ChatManager.RemoveChat(m_FriendInfo.userInfoId);

            this.chatPanel.Release();

            try
            {
                m_SendThread.Abort();
            }
            catch { }
            m_MessageQueue.Clear();

            EngineContext.Current.ChatConfig.SaveConfig();

            if (frmChatRecord != null && !frmChatRecord.IsDisposed)
            {
                frmChatRecord.Close();
            }

            GC.Collect();
        }

        //悬浮至好友Q名时
        private void lblChatName_MouseEnter(object sender, EventArgs e)
        {
            lblChatName.Font = new Font("微软雅黑", 14F, FontStyle.Underline);
        }

        //离开好友Q名时
        private void lblChatName_MouseLeave(object sender, EventArgs e)
        {
            lblChatName.Font = new Font("微软雅黑", 14F);
        }

        //关闭
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        //渐变层
        private void FrmChat_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            SolidBrush sb = new SolidBrush(Color.FromArgb(150, 255, 255, 255));
            g.FillRectangle(sb, new Rectangle(new Point(1, 91), new Size(Width - 2, Height - 91 - 33)));
        }

        /// <summary>
        /// 点击我的空间图标
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void imgyy2_Click(object sender, EventArgs e)
        {
            string url = ServiceUrlProxy.GetInstance().MyZOOMURL(m_CurrentUser.UserName, m_CurrentUser.CID);
            FrmGroup.OpenWithChrome(url);
        }

        private void lblChatQm_Click(object sender, EventArgs e)
        {
            if (m_AnnounceConfigInfo == null || string.IsNullOrEmpty(m_AnnounceConfigInfo.showAnnounce))
                return;

            FrmMessage fm = new FrmMessage("通知",
                    m_AnnounceConfigInfo.showAnnounce, m_AnnounceConfigInfo.url);

            fm.ShowDialog();
        }

        #endregion

        #region 接受消息任务栏闪烁

        private void flashTimer_Tick(object sender, EventArgs e)
        {
            WinApi.FlashWindow(this.Handle, true);
        }

        private void FrmChat_Activated(object sender, EventArgs e)
        {
            flashTimer.Enabled = false;

            InitChatConfig();
        }

        public void MyFlashWindow(Form window, bool invert)
        {
            flashTimer.Enabled = true;
        }

        #endregion

        #region 公共方法


        #endregion

        #region 私有方法

        //文件发送方法
        private bool FileSend(string filePath)
        {
            tsbUploadFile_Click(tsbUploadFile, null);

            return uploadPanel.AddUploadItem(filePath, m_ObjTalker, (shareResultInfo) =>
              {
                  chatPanel.WriteNoticeToRichTextBox(shareResultInfo.CompeledStr);

                  if (shareResultInfo.IsSucess || !string.IsNullOrEmpty(shareResultInfo.downloadUrl))
                  {
                      MessageContent msg = new MessageContent();
                      msg.Content = m_CurrentUser.UserName + "分享了文件" + shareResultInfo.downloadUrl;//获得消息文本内容
                      msg.ContentUrl = shareResultInfo.downloadUrl;
                      msg.FromId = m_CurrentUser.UserId;
                      msg.FromName = m_CurrentUser.UserName;
                      m_ChatMessage.SendMessage(msg, null, m_CurrentUser.CID);
                  }
              });
        }

        #endregion

        #region 实现 IChat接口

        /// <summary>
        /// 更新会话
        /// </summary>
        public void UpdateChat()
        {
            this.UpdateChatMessage();
        }

        /// <summary>
        /// 链接成功
        /// </summary>
        public void ConnectionSucc()
        {
            this.Enabled = true;
        }

        /// <summary>
        /// 连接失败
        /// </summary>
        public void ConnectionFail()
        {
            this.Enabled = false;
        }

        #endregion

        #region 窗体右侧控件相关事件

        /// <summary>
        /// 打开应用列表选项卡
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbAppList_Click(object sender, EventArgs e)
        {
            tsbAppList.BackgroundImage = Resources.tabBg;
            tsbUploadFile.BackgroundImage = null;
            uploadPanel.Visible = false;
            appPanel.Visible = true;
        }

        /// <summary>
        /// 打开下载文件选项卡
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbUploadFile_Click(object sender, EventArgs e)
        {
            tsbAppList.BackgroundImage = null;
            tsbUploadFile.BackgroundImage = Resources.tabBg;
            uploadPanel.Visible = true;
            appPanel.Visible = false;
        }

        #endregion

        #region 应用列表

        /// <summary>
        /// 初始化应用列表
        /// </summary>
        private void InitPersonAppList()
        {
            AsyncClient.AsyncCall<List<ButtonConfigInfo>>(() =>
            {
                PersonAppConfigParse appConfigParse = new PersonAppConfigParse();
                return appConfigParse.Parse();
            },
            (configInfoList) =>
            {
                ChatMessageItem appItems = new ChatMessageItem("应用列表");
                appItems.SubItems.Clear();
                appItems.IsOpen = true;
                appPanel.Items.Add(appItems);
                configInfoList.ForEach(x =>
                {
                    ChatMessageSubItem subItem = new ChatMessageSubItem();
                    subItem.Tag = x;
                    subItem.HeadImage = Image.FromFile(x.imgNormal);
                    subItem.ID = string.Empty;
                    subItem.DisplayName = x.tip ?? string.Empty;
                    subItem.NicName = x.tip ?? string.Empty;
                    appItems.SubItems.Add(subItem);
                });
            });
        }

        /// <summary>
        /// 双击应用项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void appPanel_DoubleClickSubItem(object sender, ChatMessageEventArgs e)
        {
            ChatMessageSubItem item = e.SelectSubItem;
            if (item != null && item.Tag is ButtonConfigInfo)
            {
                ButtonConfigInfo config = item.Tag as ButtonConfigInfo;
                string url = GroupChat2013.Common.Helper.AddUrlParams(config.link, "cid=" + EngineContext.Current.CurrUserInfo.CID);
                FrmGroup.OpenWithChrome(url);
            }
        }

        #endregion

        #region 初始化通知栏

        /// <summary>
        /// 初始化通知栏
        /// </summary>
        public void InitAnnounce()
        {
            ParseConfig<AnnounceConfigInfo> parseConfig = new ParseConfig<AnnounceConfigInfo>(EngineContext.Current.FilePathManager.PersonConfigPath,
                ConstClass.AnnounceConfig,
                () => { return new AnnounceConfigInfo(); });
            m_AnnounceConfigInfo = parseConfig.Parse();

            //设置通知栏信息
            lblChatQm.Text = m_AnnounceConfigInfo.showAnnounce;
        }

        #endregion

        #region 添加到最近聊天

        public void AddRecChat()
        {
            if (m_RecChatRepository == null)
                m_RecChatRepository = new RecChatRepository(EngineContext.Current.FilePathManager.DbPath);

            RecChatInfo chatInfo = new RecChatInfo()
            {
                ChatId = m_FriendInfo.userInfoId,
                ChatName = m_FriendInfo.loginName,
                NickName=m_FriendInfo.nickname,
                ChatType = ChatType.User,
                HeadUrl = string.Empty,
                CreateTime = DateTime.Now
            };

            m_RecChatRepository.AddRecChatInfo(chatInfo);
        }

        #endregion

    }
}
